#include "pch.h"

#include "math/directx/dxmatrix.h"
#include "core/config.h"


#ifdef RE_USE_DX


namespace Math
{

	//////////////////////////////////////////////////////////////////////////
	matrix::matrix():
	m_matrix(XMMatrixIdentity())
	{
		// TODO
	}

	//////////////////////////////////////////////////////////////////////////
	matrix::matrix( const float4& r1, const float4& r2, const float4& r3, const float4& r4 )
	{
		this->m_matrix.r[0] = r1.m_vec;
		this->m_matrix.r[1] = r2.m_vec;
		this->m_matrix.r[2] = r3.m_vec;
		this->m_matrix.r[3] = r4.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	matrix::matrix( const XMMATRIX& rhs ):
	m_matrix(rhs)
	{
		// TODO
	}





	//////////////////////////////////////////////////////////////////////////
	void matrix::operator =( const matrix& rhs )
	{
		this->m_matrix = rhs.m_matrix;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::operator =( const XMMATRIX& rhs )
	{
		this->m_matrix = rhs;
	}

	//////////////////////////////////////////////////////////////////////////
	bool matrix::operator ==( const matrix& rhs ) const
	{
		return (XMVector4Equal(this->m_matrix.r[0], rhs.m_matrix.r[0]) &&
				XMVector4Equal(this->m_matrix.r[1], rhs.m_matrix.r[1]) &&
				XMVector4Equal(this->m_matrix.r[2], rhs.m_matrix.r[2]) &&
				XMVector4Equal(this->m_matrix.r[3], rhs.m_matrix.r[3]));
	}

	//////////////////////////////////////////////////////////////////////////
	bool matrix::operator !=( const matrix& rhs ) const
	{
		return (XMVector4NotEqual(this->m_matrix.r[0], rhs.m_matrix.r[0]) ||
				XMVector4NotEqual(this->m_matrix.r[1], rhs.m_matrix.r[1]) ||
				XMVector4NotEqual(this->m_matrix.r[2], rhs.m_matrix.r[2]) ||
				XMVector4NotEqual(this->m_matrix.r[3], rhs.m_matrix.r[3]));
	}





	//////////////////////////////////////////////////////////////////////////
	void matrix::set( const float4& r1, const float4& r2, const float4& r3, const float4& r4 )
	{
		this->m_matrix.r[0] = r1.m_vec;
		this->m_matrix.r[1] = r2.m_vec;
		this->m_matrix.r[2] = r3.m_vec;
		this->m_matrix.r[3] = r4.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::setr1( const float4& r )
	{
		this->m_matrix.r[0] = r.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::setr2( const float4& r )
	{
		this->m_matrix.r[1] = r.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::setr3( const float4& r )
	{
		this->m_matrix.r[2] = r.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::setr4( const float4& r )
	{
		this->m_matrix.r[3] = r.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	const float4& matrix::getr1() const
	{
		return *(float4*)&(this->m_matrix.r[0]);
	}

	//////////////////////////////////////////////////////////////////////////
	const float4& matrix::getr2() const
	{
		return *(float4*)&(this->m_matrix.r[1]);
	}

	//////////////////////////////////////////////////////////////////////////
	const float4& matrix::getr3() const
	{
		return *(float4*)&(this->m_matrix.r[2]);
	}

	//////////////////////////////////////////////////////////////////////////
	const float4& matrix::getr4() const
	{
		return *(float4*)&(this->m_matrix.r[3]);
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::setxaxis( const float4& a )
	{
		this->m_matrix.r[0] = a.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::setyaxis( const float4& a )
	{
		this->m_matrix.r[1] = a.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::setzaxis( const float4& a )
	{
		this->m_matrix.r[2] = a.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::setposition( const float4& pos )
	{
		this->m_matrix.r[3] = pos.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	const float4& matrix::getxaxis() const
	{
		return *(float4*)&(this->m_matrix.r[0]);
	}

	//////////////////////////////////////////////////////////////////////////
	const float4& matrix::getyaxis() const
	{
		return *(float4*)&(this->m_matrix.r[1]);
	}

	//////////////////////////////////////////////////////////////////////////
	const float4& matrix::getzaxis() const
	{
		return *(float4*)&(this->m_matrix.r[2]);
	}

	//////////////////////////////////////////////////////////////////////////
	const float4& matrix::getposition() const
	{
		return *(float4*)&(this->m_matrix.r[3]);
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::scale( const float4& s )
	{
		float4 scr = s;
		scr.setw(1.0f);

		this->m_matrix.r[0] = float4::multiply(this->m_matrix.r[0], scr).m_vec;
		this->m_matrix.r[1] = float4::multiply(this->m_matrix.r[1], scr).m_vec;
		this->m_matrix.r[2] = float4::multiply(this->m_matrix.r[2], scr).m_vec;
		this->m_matrix.r[3] = float4::multiply(this->m_matrix.r[3], scr).m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	void matrix::translate( const float4& f )
	{
		this->m_matrix.r[3] += f.m_vec;
	}

	//////////////////////////////////////////////////////////////////////////
	bool matrix::isidentity() const
	{
		return (XMMatrixIsIdentity(this->m_matrix) != 0);
	}

	//////////////////////////////////////////////////////////////////////////
	scalar matrix::determinant() const
	{
		return float4::unwrapw(XMMatrixDeterminant(this->m_matrix));
	}





	//////////////////////////////////////////////////////////////////////////
	matrix matrix::identity()
	{
		return XMMatrixIdentity();
	}

	matrix matrix::affinetransformation( scalar s, const float4& rC, const quaternion& r, const float4& t )
	{
		return XMMatrixAffineTransformation(float4::wrap(s).m_vec, rC.m_vec, r.m_vec, t.m_vec);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::inverse( const matrix& m )
	{
		XMVECTOR temp;

		return XMMatrixInverse(&temp, m.m_matrix);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::multiply( const matrix& m1, const matrix& m2 )
	{
		return XMMatrixMultiply(m1.m_matrix, m2.m_matrix);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::lookatlh( const float4& eye, const float4& at, const float4& up )
	{
		return XMMatrixLookAtLH(eye.m_vec, at.m_vec, up.m_vec);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::lookatrh( const float4& eye, const float4& at, const float4& up )
	{
		return XMMatrixLookAtRH(eye.m_vec, at.m_vec, up.m_vec);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::ortholh( scalar w, scalar h, scalar zn, scalar zf )
	{
		return XMMatrixOrthographicLH(w, h, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::orthorh( scalar w, scalar h, scalar zn, scalar zf )
	{
		return XMMatrixOrthographicRH(w, h, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::orthooffcenterlh( scalar l, scalar r, scalar b, scalar t, scalar zn, scalar zf )
	{
		return XMMatrixOrthographicOffCenterLH(l, r, b, t, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::orthooffcenterrh( scalar l, scalar r, scalar b, scalar t, scalar zn, scalar zf )
	{
		return XMMatrixOrthographicOffCenterRH(l, r, b, t, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::perspectivefovlh( scalar fovy, scalar aspect, scalar zn, scalar zf )
	{
		return XMMatrixPerspectiveFovLH(fovy, aspect, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::perspectivefovrh( scalar fovy, scalar aspect, scalar zn, scalar zf )
	{
		return XMMatrixPerspectiveFovRH(fovy, aspect, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::perspectivelh( scalar w, scalar h, scalar zn, scalar zf )
	{
		return XMMatrixPerspectiveLH(w, h, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::perspectiverh( scalar w, scalar h, scalar zn, scalar zf )
	{
		return XMMatrixPerspectiveRH(w, h, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::perspectiveoffcenterlh( scalar l, scalar r, scalar b, scalar t, scalar zn, scalar zf )
	{
		return XMMatrixPerspectiveOffCenterLH(l, r, b, t, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::perspectiveoffcenterrh( scalar l, scalar r, scalar b, scalar t, scalar zn, scalar zf )
	{
		return XMMatrixPerspectiveOffCenterRH(l, r, b, t, zn, zf);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::reflect( const plane& p )
	{
		return XMMatrixReflect(p.m_vec);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::rotationaxis( const float4& axis, scalar angle )
	{
		return XMMatrixRotationAxis(axis.m_vec, angle);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::rotationquaternion( const quaternion& q )
	{
		return XMMatrixRotationQuaternion(q.m_vec);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::rotationx( scalar a )
	{
		return XMMatrixRotationX(a);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::rotationy( scalar a )
	{
		return XMMatrixRotationY(a);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::rotationz( scalar a )
	{
		return XMMatrixRotationZ(a);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::rotationpitchyawroll( scalar pitch, scalar yaw, scalar roll )
	{
		return XMMatrixRotationRollPitchYaw(pitch, yaw, roll);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::scaling( scalar sx, scalar sy, scalar sz )
	{
		return XMMatrixScaling(sx, sy, sz);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::scaling( const float4& s )
	{
		return XMMatrixScalingFromVector(s.m_vec);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::transformation( const float4& sC, const quaternion& sR, const float4& s, const float4& rC, const quaternion& r, const float4& t )
	{
		return XMMatrixTransformation(sC.m_vec, sR.m_vec, s.m_vec, rC.m_vec, r.m_vec, t.m_vec);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::translation( scalar x, scalar y, scalar z )
	{
		return XMMatrixTranslation(x, y, z);
	}

	//////////////////////////////////////////////////////////////////////////
	matrix matrix::transpose( const matrix& m )
	{
		return XMMatrixTranspose(m.m_matrix);
	}

	//////////////////////////////////////////////////////////////////////////
	float4 matrix::transform( const float4& f, const matrix& m )
	{
		return XMVector4Transform(f.m_vec, m.m_matrix);
	}

	//////////////////////////////////////////////////////////////////////////
	quaternion matrix::rotationmatrix( const matrix& m )
	{
		return XMQuaternionRotationMatrix(m.m_matrix);
	}

	//////////////////////////////////////////////////////////////////////////
	plane matrix::transform( const plane& p, const matrix& m )
	{
		return XMPlaneTransform(p.m_vec, m.m_matrix);
	}

}

#endif // RE_USE_DX